﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DZPK.SocketImpl
{
    public class ByteArray
    {
        //public Endian endian;
        public uint position;
        public uint length;
        public List<byte> array;

        public ByteArray()
        {
            array = new List<byte>();
            length = 0;
            position = 0;
        }

        public void Reset()
        {
            array = new List<byte>();
            length = 0;
            position = 0;
        }

        public byte[] GetByteArrayData()
        {
            return array.ToArray();
        }

        // write a byte to the byte stream
        public void writeByte(int value)
        {
            //array.Add((byte)(value & 0xFF));
            if (position < length)
            {
                array[(int)position++] = (byte)(value & 0xFF);
            }
            else 
            {
                length++;
                position++;
                array.Add((byte)(value & 0xFF));
            }
        }

        // write a 16-bit int to the byte stream.
        public void writeShort(int value)
        {
            //array.Add((byte)(value & 0xFF));
            //array.Add((byte)((value & 0xFF00) >> 8));
            if (position + 2 < length)
            {
                array[(int)position++] = (byte)(value & 0xFF);
                array[(int)position++] = (byte)((value & 0xFF00) >> 8);
            }
            else 
            {
                length += 2;
                position += 2;
                array.Add((byte)(value & 0xFF));
                array.Add((byte)((value & 0xFF00) >> 8));

            }
        }

        public void writeInt(int value)
        {
            // little endian mode by default
            //byte b1 = (byte)(value & 0xFF);
            //byte b2 = (byte)((value & 0xFF00) >> 8);
            //byte b3 = (byte)((value & 0xFF0000) >> 16);
            //byte b4 = (byte)((value & 0xFF000000) >> 24);

            //array.Add(b1);
            //array.Add(b2);
            //array.Add(b3);
            //array.Add(b4);

            //array.Add((byte)(value & 0xFF));
            //array.Add((byte)((value & 0xFF00) >> 8));
            //array.Add((byte)((value & 0xFF0000) >> 16));
            //array.Add((byte)((value & 0xFF000000) >> 24));

            if (position + 4 < length)
            {
                array[(int)position++] = (byte)(value & 0xFF);
                array[(int)position++] = (byte)((value & 0xFF00) >> 8);
                array[(int)position++] = (byte)((value & 0xFF00) >> 16);
                array[(int)position++] = (byte)((value & 0xFF00) >> 24);
            }
            else
            {
                length += 4;
                position += 4;

                array.Add((byte)(value & 0xFF));
                array.Add((byte)((value & 0xFF00) >> 8));
                array.Add((byte)((value & 0xFF0000) >> 16));
                array.Add((byte)((value & 0xFF000000) >> 24));
            }
        }

        public void writeUnsignedInt(uint value)
        {
            //array.Add((byte)(value & 0xFF));
            //array.Add((byte)((value & 0xFF00) >> 8));
            //array.Add((byte)((value & 0xFF0000) >> 16));
            //array.Add((byte)((value & 0xFF000000) >> 24));

            if (position + 4 < length)
            {
                array[(int)position++] = (byte)(value & 0xFF);
                array[(int)position++] = (byte)((value & 0xFF00) >> 8);
                array[(int)position++] = (byte)((value & 0xFF00) >> 16);
                array[(int)position++] = (byte)((value & 0xFF00) >> 24);
            }
            else
            {
                length += 4;
                position += 4;

                array.Add((byte)(value & 0xFF));
                array.Add((byte)((value & 0xFF00) >> 8));
                array.Add((byte)((value & 0xFF0000) >> 16));
                array.Add((byte)((value & 0xFF000000) >> 24));
            }
        }
       
        public void writeMultiByte(string value, string charSet)
        {
            byte[] bytes = new byte[0];

            if (charSet.Equals("utf-8", StringComparison.OrdinalIgnoreCase))
            {
                bytes = System.Text.Encoding.UTF8.GetBytes(value);
            }
            else if (charSet.Equals("gb2312", StringComparison.OrdinalIgnoreCase))
            {
                bytes = System.Text.Encoding.GetEncoding("GB2312").GetBytes(value);
            }
            else 
            {
                bytes = System.Text.Encoding.Default.GetBytes(value);
            }

            if (position + bytes.Length < length)
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    array[(int)position + i] = bytes[i];
                }
            }
            else 
            {
                length += (uint)bytes.Length;
                position += (uint)bytes.Length;
                array.AddRange(bytes);
            }
        }

        public void writeBytes(ByteArray bytes, uint offset = 0, uint length = 0)
        {
            if (length == 0)
            {
                length = bytes.length;
            }

            for (int i = (int)offset; i < offset + length; i++)
            {
                //array.Add((byte)bytes[i]);
                writeByte((byte)bytes[i]);
            }
        }

        public void writeArrayBytes(byte[] bytes)
        {
            position += (uint)bytes.Length;
            length += (uint)bytes.Length;
            array.AddRange(bytes);
        }

        public void writeObject(object obj)   // ?? how to implement?
        {
            throw new NotImplementedException();
        }

        public byte this[int i]
        {
            get 
            {
                return array[i];
            }
            set
            {
                array[i] = (byte)(value & 0xFF);
            }
        }

        public short readShort()
        {
            int ret = (int)array[(int)position++] + ((int)array[(int)position++] << 8);
            short sret = (short)(ret & 0xFFFF);
            return sret;
        }

        public int readByte()
        {
            return (int)array[(int)position++];
        }

        public int readBytes(ByteArray bytes, uint offset = 0, uint length = 0)
        {
            if (length == 0)
            {
                length = this.length;
            }

            int readLength = (int)length;

            for (int i = (int)offset; i < offset + length; i++)
            {
                bytes.writeByte(array[i]);
            }

            return readLength;
        }

        public int readInt()
        {
            //int i1 = (int)array[(int)position++] ;
            //int i2 = (int)array[(int)position++] << 8;
            //int i3 = (int)array[(int)position++] << 16;
            //int i4 = (int)array[(int)position++] << 24;

            //int read = i4 + i3 + i2 + i1;

            //return read;

            return (int)array[(int)position++] + ((int)array[(int)position++] << 8) + ((int)array[(int)position++] << 16) + ((int)array[(int)position++] << 24);
        }

        public uint readUnsignedInt()
        {
            uint read = (uint)((int)array[(int)position++] + ((int)array[(int)position++] << 8) + ((int)array[(int)position++] << 16) + ((int)array[(int)position++] << 24));

            return read;
        }

        public Int64 readInt64()
        {
            uint low = readUnsignedInt();
            int high = readInt();
            Int64 ret64 = ((high * (long)Math.Pow(2, 32)) + low);
            return ret64;
        }

        public string readMultiByte(uint length, string charSet)
        {
            byte[] bytes = new byte[length];

            for (int i = 0; i < (int)length; i++)
            {
                bytes[i] = (byte)readByte();
            }

            string ret;

            if (charSet.Equals("utf-8", StringComparison.OrdinalIgnoreCase))
            {
                ret = Encoding.UTF8.GetString(bytes);
            }
            else if (charSet.Equals("gb2312", StringComparison.OrdinalIgnoreCase))
            {
                ret = Encoding.GetEncoding("GB2312").GetString(bytes);
            }
            else
            {
                ret = Encoding.Default.GetString(bytes);
            }

            return ret;
        }

        public object readObject()
        {
            throw new NotImplementedException();
        }
    }
}
